package com.ztl.jni;

import java.io.DataOutputStream;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.Arrays;

import android.annotation.SuppressLint;
import android.util.Log;

public class ZtlCanManager {
	private static final String TAG = "ZtlCan";
	private int fd;
	private boolean mCloseFd = true;
	public boolean mDebug = true;
	private boolean mReciThreadExit = true;
//	public native static int init();
//	public native static int openCan(String canx);
//	
//	public native static int   closeCan( int fd);
//	public native static int   sendCan(int fd, long canid, long eff, long rtr, int len, int[] data) ;
//	public native static byte[]  receiveCan(int fd) ;
	
	public int init(String canx, int baudrate){
		CanService.init();
		if ( !canx.startsWith("can")) {
	        Log.e(TAG, "can name error, must start by can" );
	        return -1;
	    }
	    if (baudrate < 0) {	    	
	        return -2;
	    }	 
	    try {
	        //ShellUtils.execCmd("ip link set " + canx + " type can tq 133 prop-seg 6 phase-seg1 6 phase-seg2 2 sjw 1", true);
//	        ShellUtils.CommandResult commandResult = ShellUtils.execCmd("ip link set " + canx + " down && ip link set " + canx + " type can bitrate " + baudrate + " && ip link set " + canx + " up", true);
	    	execRootCmdSilent("ip link set " + canx + " down && ip link set " + canx + " type can bitrate " + baudrate + " && ip link set " + canx + " up");
	    } catch (Exception e) {
	        Log.e(TAG, "Error setting up CAN system: " + e.getMessage());
	    }
		return 0;		
	}
	
	public ZtlCanManager() {
	    
	}
	
	public ZtlCanManager(ZtlCanCallback callback) {
	    mCallback = callback;
	}
	
	public int openCan(String canx){
        if(mCloseFd==false)return fd;
		fd = CanService.openCan(  canx);
		if(fd>0) mCloseFd = false;
		return fd;
	}
	
	public  void closeCan(){
	    int iExitCount = 0;

		if(fd >= 0){
            mCloseFd = true;
		    CanService.closeCan(  fd);

		    while(!mReciThreadExit){
                try {
                    if(iExitCount++<100)
                        Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        mCloseFd = true;

	}
	
	public  int   sendCan(  long canid, long eff, long rtr, int len, byte[] data) {
		return CanService.sendCan(fd,  canid,   eff,   rtr,   len,   data);
	}
	
	/*
	 * canid id帧
	 * eff   拓展帧
	 * rtr   远程帧
	 */
	public  int   sendCan(  long canid, long eff, long rtr, String strdata) {
		byte[] byteArrayCan = hexStringToByteArray(strdata);
		return CanService.sendCan(fd,  canid,   eff,   rtr,   byteArrayCan.length,   byteArrayCan );
	}
	
	private int  receiveCan(byte[] retByteArray) {
		return CanService.receiveCan(fd,retByteArray);
	}
	
	public static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        byte[] byteArray = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            if(i+1>=len){
                break;
            }
            char c = hexString.charAt(i);
            int digit1 = Character.digit(c, 16);//取出相应
            int number = digit1 << 4;
            char c1 = hexString.charAt(i + 1);
            int digit = Character.digit(c1, 16);
            byteArray[i / 2] = (byte) (number + digit);
        }
        return byteArray;
    }
	
	public static String bytesToHex(byte[] bytes,String str) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                // 如果是一位的话，要补0
                hexString.append('0');
            }
            hexString.append(hex);
            if(str!=null)
            	hexString.append(str);
        }
        return hexString.toString();
    }
	
	/**
	 * 回调接口
	 *
	 */

	private ZtlCanCallback mCallback = null;


	public void startCanReceiverThread() { // 新增的方法，用来启动接收CAN数据的线程
        mReciThreadExit = false;
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] retByteArray = new byte[15]; // 修改数组大小为15
                int count = 0;
                boolean bEff;
                boolean bRtr;
//            	long canId;
                byte[] canByteData;
                int dataLen;
                int ret;
                while (!mCloseFd) {
                    ret = receiveCan(retByteArray);
                    if(ret < 0){
                    	Log.d(TAG, "startCanReceiverThread ret error :"+ret  );
                        break;
                    }
                    if(ret == 0){
                        continue;
                    }

                    count++;
//                    needBlinkForReceive.set(true);

                    // 解析canId为一个32位的整数
                    // long canId = ((ret[0] & 0xFF) << 24) | ((ret[1] & 0xFF) << 16) | ((ret[2] & 0xFF) << 8) | (ret[3] & 0xFF);
                    long canId = ((retByteArray[0] & 0xFFL) << 24) | ((retByteArray[1] & 0xFFL) << 16) | ((retByteArray[2] & 0xFFL) << 8) | (retByteArray[3] & 0xFFL);
                    // long canId = (((long)ret[0] & 0xFF) << 24) | (((long)ret[1] & 0xFF) << 16) | (((long)ret[2] & 0xFF) << 8) | ((long)ret[3] & 0xFF);

                    byte canEff = retByteArray[4];
                    byte canRtr = retByteArray[5];
                    byte canLen = retByteArray[6];
                    byte[] canData = Arrays.copyOfRange(retByteArray, 7, 7 + canLen); // 从ret[7]开始复制
                    String str = "can RX ";
                    bEff = (canEff == 1);
                    bRtr = (canRtr == 1);
                    String canIdStr = Long.toHexString(canId);
                    if (canEff == 0) {
                        for (int i = 0; i < 3 - canIdStr.length(); i++) {
                            canIdStr = '0' + canIdStr;
                        }
                    } else {
                        for (int i = 0; i < 8 - canIdStr.length(); i++) {
                            canIdStr = '0' + canIdStr;
                        }
                    }
                    if(mDebug){
                        str += !bEff ? "S " : "E ";
                        str += !bRtr ? "-  " : "R  ";
                        str = str + canIdStr + "   [" + Long.toString(canLen) + "]  ";
                        String strCanData = "" ;
//                        strCanDatabytesToHex(canData)
                        strCanData = bytesToHex(canData," ").toUpperCase();

                        str = str.toUpperCase()+strCanData;
                        str += '\n';
                        String finalStr = str;
                        Log.d(TAG, "Received CAN data: count:" + count +", finalStr:"+finalStr);
                    }

                    if(mCallback!=null){
                        mCallback.get_recv_can_data(bEff, bRtr, canIdStr, canData, canLen);
                    }
                }
                mReciThreadExit = true;
                Log.d(TAG, "Received CAN  exit: " + mCloseFd );
            }
        }).start();



    }

	
	static public int execRootCmdSilent(String cmd) { 
        int result = -1; 
        DataOutputStream dos = null; 
         
        try { 
//            Process p = Runtime.getRuntime().exec("su");
        	File fileSu = new File("/system/xbin/testsu");
            Process p;
        	if(fileSu.exists()){
        		p = Runtime.getRuntime().exec("testsu"); 
        	}else{
        		p = Runtime.getRuntime().exec("su"); 
        	}
            dos = new DataOutputStream(p.getOutputStream()); 
             
            System.out.println(cmd); 
            dos.writeBytes(cmd + "\n"); 
            dos.flush(); 
            dos.writeBytes("exit\n"); 
            dos.flush(); 
            result = p.waitFor(); 
//            result = p.exitValue(); 
            System.out.println(result);
        } catch (Exception e) { 
            e.printStackTrace(); 
        } finally { 
            if (dos != null) { 
                try { 
                    dos.close(); 
                } catch (Exception e) { 
                    e.printStackTrace(); 
                } 
            } 
        } 
        return result; 
    }
}
